﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;

namespace NGuice.Inject.Internal.Util
{
    public static  class Classes
    {
        public static bool IsInnerClass(Type clazz)
        {
            return clazz.IsNested;
        }

        public static bool IsConcrete(Type clazz)
        {
            return !clazz.IsInterface && !clazz.IsAbstract;
        }

        public static string ToString(MemberInfo member)
        {
            Type memberType = Classes.MemberType(member);

            if (memberType == typeof(MethodInfo))
            {
                return member.DeclaringType.FullName + "." + member.Name + "()";
            }
            else if (memberType == typeof(FieldInfo))
            {
                return member.DeclaringType.FullName + "." + member.Name;
            }
            else if (memberType == typeof(ConstructorInfo))
            {
                return member.DeclaringType.FullName + ".ctor()";
            }
            else
            {
                Trace.Fail("");
                return null;
            }
        }

        public static Type MemberType(MemberInfo member)
        {
            Preconditions.CheckNotNull(member, "member");
            if (member is FieldInfo)
            {
                return typeof(FieldInfo);
            }
            else if (member is MethodInfo)
            {
                return typeof(MethodInfo);
            }
            else if (member is ConstructorInfo)
            {
                return typeof(ConstructorInfo);
            }
            else
            {
                throw new ArgumentException("Unsupported implementation class for Member, " + member.Name);
            }
        }

        public static string GetMethodDescriptor(MethodInfo method)
        {
            StringBuilder sb = new StringBuilder().Append(method.Name).Append("(");
            int length = method.GetParameters().Length;
            int index = 0;
            foreach (var p in method.GetParameters())
            {
                sb.Append(p.ParameterType.FullName);
                if (index++ < length - 1)
                    sb.Append(", ");
                else
                    sb.Append(")");
            }
            return sb.ToString();
        }

        public static string GetConstructorDescriptor(ConstructorInfo ctor)
        {
            StringBuilder sb = new StringBuilder().Append(".ctor(");
            int length = ctor.GetParameters().Length;
            int index = 0;
            foreach (var p in ctor.GetParameters())
            {
                sb.Append(p.ParameterType.FullName);
                if (index++ < length - 1)
                    sb.Append(", ");
                else
                    sb.Append(")");
            }
            return sb.ToString();
        }

        /// <summary>
        /// 返回表示按照声明顺序对此 Method 对象所表示方法的形参进行注释的那个数组的数组。
        /// （如果底层方法没有参数，则返回长度为零的数组。如果该方法有一个或多个参数，则为每个不带注释的参数返回长度为零的嵌套数组。）
        /// </summary>
        public static Attribute[][] GetParameterAttributes(this MethodBase method)
        {
            ParameterInfo[] param = method.GetParameters();
            Attribute[][] attribute = new Attribute[param.Length][];
            int i = 0;
            foreach (ParameterInfo p in param)
            {
                object[] o = p.GetCustomAttributes(false);
                Attribute[] attr = new Attribute[o.Length];
                for (int j = 0; j < attr.Length; j++)
                {
                    attr[j] = o[j] as Attribute;
                }
                attribute[i++] = attr;
            }
            return attribute;
        }
    }
}
